"""
完成一种直线裁剪算法
"""
#导入库
import numpy as np
import matplotlib.pyplot as plt

#声明全局变量
global xl, xr, yb, yt

#梁友栋-barsky算法
def L_Brasky(x0, y0, x1, y1):
    # 初始化t0和t1，t是保存参数的列表
    t = [0.0, 1.0]  
    # 计算线段在 x 方向上的增量
    deltax = x1 - x0  
    # 判断线段左侧是否可见
    if not cansee(-deltax, x0 - xl, t):
        return False
    # 判断线段右侧是否可见
    if not cansee(deltax, xr - x0, t):
        return False
    deltay = y1 - y0  # 计算线段在 y 方向上的增量
    # 判断线段下方是否可见
    if not cansee(-deltay, y0 - yb, t):
        return False
    # 判断线段上方是否可见
    if not cansee(deltay, yt - y0, t):
        return False
    # 根据计算的参数 t 裁剪线段
    x1 = x0 + t[1] * deltax
    y1 = y0 + t[1] * deltay
    x0 = x0 + t[0] * deltax
    y0 = y0 + t[0] * deltay
    # 绘制剩余部分
    # showline(x0, y0, x1, y1)  
    # 返回剩余线段的端点坐标和布尔标志是否在窗口内
    return True, x0, y0, x1, y1  

def cansee(q, d, t):
    # 从 t 中获取当前线段在计算过程中的起点和终点的参数值
    t0, t1 = t[0], t[1]  
    # 如果 q<0，则线段增量为负，表示需要判断线段左侧是否可见
    if q < 0:  
        # 计算线段到窗口边界的位置参数 r
        r = d / q  
        # 如果 r 大于线段终点的参数值，说明该线段不可见
        if r > t1:  
            return False
        # 如果 r 在当前线段的起点和终点参数值之间，则更新当前线段的起点参数值 t0
        elif r > t0:  
            t[0] = r
    # 如果 q>0，则线段增量为正，表示需要判断线段右侧是否可见        
    elif q > 0: 
        # 计算线段到窗口边界的位置参数 r 
        r = d / q  
        # 如果 r 小于线段起点的参数值，说明该线段不可见
        if r < t0:  
            return False
        # 如果 r 在当前线段的起点和终点参数值之间，则更新当前线段的终点参数值 t1
        elif r < t1:  
            t[1] = r
    # 如果 q=0 且 d<0，则说明线段方向和窗口边界平行，且与窗口边界重合
    elif d < 0:  
        return False
    # 如果该线段可见，则返回 True
    return True  

# DDA算法
# DDA算法的函数
def DDA(x1, y1, x2, y2, color1, color2):
    # 调用裁剪算法
    if L_Brasky(x1, y1, x2, y2):
        flag, x3, y3, x4, y4 = L_Brasky(x1, y1, x2, y2)
        if x3 > x4:
            x4, x3 = x3, x4
        if y3 > y4:
            y4, y3 = y3, y4
    else:
        flag = False

    # 计算斜率
    dx = x2 - x1
    dy = y2 - y1
    # 计算步长
    e = abs(dx) if (abs(dx) > abs(dy)) else abs(dy)
    # 计算增量
    dx = dx / e
    dy = dy / e
    # 初始化坐标
    x = x1
    y = y1
    i = 1
    # 绘制直线
    while i <= e:
        if flag:
            if x3 <= x <= x4 and y3 <= y <= y4:
                img[int(x)][int(y)] = color2
            else:
                img[int(x)][int(y)] = color1
        else:
            img[int(x)][int(y)] = color1
        x = x + dx
        y = y + dy
        i = i + 1

# 按间距中的绿色按钮以运行脚本。
if __name__ == '__main__':
    # 创建一个全为0的二维数组
    img = np.zeros([500, 500, 3], dtype=np.uint8)

    # 填充255表示白色
    img[:, :, :] = [255, 255, 255]

    # 画出裁剪窗口
    xl, yb, xr, yt = 150, 150, 350, 350
    DDA(xl, yt, xl, yb, [0, 0, 0], [0, 0, 0])
    DDA(xl, yb, xr, yb, [0, 0, 0], [0, 0, 0])
    DDA(xr, yb, xr, yt, [0, 0, 0], [0, 0, 0])
    DDA(xr, yt, xl, yt, [0, 0, 0], [0, 0, 0])

    # 画出线
    DDA(50, 50, 400, 230, [0, 0, 255], [255, 0, 0])
    DDA(101, 142, 170, 230, [0, 0, 255], [255, 0, 0])
    DDA(300, 250, 100, 330, [0, 0, 255], [255, 0, 0])
    DDA(250, 200, 400, 400, [0, 0, 255], [255, 0, 0])
    DDA(100, 50, 200, 320, [0, 0, 255], [255, 0, 0])
    DDA(220, 130, 250, 440, [0, 0, 255], [255, 0, 0])
    DDA(80, 220, 300, 100, [0, 0, 255], [255, 0, 0])

    img1 = np.transpose(img, (1, 0, 2))
    plt.imshow(img1, origin='lower')
    plt.title('MyImage')
    plt.show()
